
//
//  WaterFallView.m
//  瀑布流
//
//  Created by mac on 2017/3/15.
//  Copyright © 2017年 mac. All rights reserved.
//使用瀑布流形式展示内容的控件

#import "WaterFallView.h"
#import "WaterFallViewCell.h"


//总列数
#define NumberOfColums 3
//默认margin
#define DefaultMargin 5
//cell默认高度
#define DefaultCellHeight 80

@interface WaterFallView()
//存放每一个cell的frame
@property (nonatomic, strong) NSMutableArray *cellFrames;
//存放正在屏幕上展示的cell
@property (nonatomic, strong) NSMutableDictionary *displacingCells;
//缓存池：用来存放离开屏幕的cell
@property (nonatomic, strong) NSMutableSet *resuableCells;

@end


@implementation WaterFallView

//懒加载 数组
- (NSMutableArray *)cellFrames{
    if (_cellFrames == nil) {
        self.cellFrames = [NSMutableArray array];
    }
    return _cellFrames;
}

- (NSMutableDictionary *)displacingCells{
    if (_displacingCells == nil) {
        self.displacingCells = [NSMutableDictionary dictionary];
    }
    return _displacingCells;
}


- (NSMutableSet *)resuableCells{
    if (_resuableCells == nil) {
        self.resuableCells = [NSMutableSet set];
    }
    return _resuableCells;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        
    }
    return self;
}

//视图即将展示
- (void)willMoveToSuperview:(UIView *)newSuperview{

    [self reloadData];
}


- (CGFloat)cellWidth{
    
    NSUInteger numberOfColums = [self numberOfColums];
    CGFloat leftM = [self marginType:WaterFallMarginTypeLeft];
    CGFloat rightM = [self marginType:WaterFallMarginTypeRight];
    CGFloat columnM = [self marginType:WaterFallMarginTypeColumn];
    
   return (self.bounds.size.width - leftM - rightM - (numberOfColums - 1) * columnM) / numberOfColums;
}

//刷新数据
//1.计算每一个cell的frame
- (void)reloadData{
    //0.先清空原来所有数据
    //（1）清空 cellFrames
    [self.cellFrames removeAllObjects];
    //(2) displacingCells 字典中：key:下标； values:cell;所以将所有正在屏幕上展示的cell从父视图上移除
    [self.displacingCells.allValues makeObjectsPerformSelector:@selector(removeFromSuperview)];
    //(3)再把字典清空
    [self.displacingCells removeAllObjects];
    //(4)将复用池清空
    [self.resuableCells removeAllObjects];
    

    //1.计算cell的总数
    NSUInteger numberOfCells = [self.dataSource numberOfCellsInWaterfall:self];
    //2.计算有多少列
    NSUInteger numberOfColums = [self numberOfColums];
    //3.计算间距
    CGFloat topM = [self marginType:WaterFallMarginTypeTop];
    CGFloat leftM = [self marginType:WaterFallMarginTypeLeft];
    CGFloat bottomM = [self marginType:WaterFallMarginTypeBottom];
    CGFloat rightM = [self marginType:WaterFallMarginTypeRight];
    CGFloat columnM = [self marginType:WaterFallMarginTypeColumn];
    CGFloat rowM = [self marginType:WaterFallMarginTypeRow];
    //4.cell的宽度
    CGFloat cellW = [self cellWidth];
    //5.cell的高度
    //瀑布流 排布的时候，不是从左到右依次布局的，而是判断每一列的最大Y值maxY，maxY最小的列，最先布局cell
    //用C语言的数组存放所有列的最大Y值
    CGFloat maxYOfColumns[numberOfColums];
    for (int i = 0; i < numberOfColums; i++) {
        maxYOfColumns[i] = 0.0;
    }
    //计算cell的frame
    for (int i = 0; i < numberOfCells; i++) {
        //记录在哪一列(默认第0列)
        NSUInteger cellColumn = 0;
        //记录cell所在那一列的最大Y值（最短那一列的最大Y值）
        CGFloat maxY = maxYOfColumns[cellColumn];
        //求出最短的那一列
        for (int j = 0; j < numberOfColums; j ++) {
            if (maxYOfColumns[j] < maxY) {
                cellColumn = j;
                maxY = maxYOfColumns[j];
            }
        }
        
        CGFloat cellH = [self heightAtIndex:i];
        
        //6.计算cell 的X/Y
        CGFloat cellX = leftM + (cellW + columnM) * cellColumn;
        CGFloat cellY = 0;
        if (maxY == 0.0) {
            //说明是第一行
            cellY = topM;
        }else{
            cellY = maxY + rowM;
        }
        
        CGRect cellFrame = CGRectMake(cellX, cellY, cellW, cellH);
        //注意：数组中不能直接存放结构体，cellFrame需要转换一下
        [self.cellFrames addObject:[NSValue valueWithCGRect:cellFrame]];
        
        //更新最短那一列的最大Y值
        maxYOfColumns[cellColumn] = CGRectGetMaxY(cellFrame);
        
        //7.显示cell
//        WaterFallViewCell *cell = [self.dataSource waterFallView:self cellAtIndex:i];
//        cell.frame = cellFrame;
//        [self addSubview:cell];
    }
    
    //8.设置contentSize,scrollView才能滚动
    CGFloat contentH = maxYOfColumns[0];
    //因为默认 最大值是第0个，所以从1开始和最大值比较
    for (int k = 1; k < numberOfColums; k++) {
        if (maxYOfColumns[k] > contentH) {
            contentH = maxYOfColumns[k];
        }
    }
    
    contentH += bottomM;
    
    self.contentSize = CGSizeMake(0, contentH);
    
}

- (void)layoutSubviews{
    [super layoutSubviews];
    //    NSLog(@"========");
    //scrollView 滚动会调用这个方法
    //监听 scrollView 的滚动
    //向数据源索要对应位置的cell(显示在屏幕上的cell)
    NSUInteger numberOfCells = self.cellFrames.count;
    for (int i = 0; i < numberOfCells; i++) {
        //1.取出i位置对应的frame
        CGRect cellFrame = [self.cellFrames[i] CGRectValue];
        
        //2.优先从字典中取出i对应的cell
        WaterFallViewCell *cell = self.displacingCells[@(i)];
        
        //3.判断cell是否在屏幕上
        if ([self isInframe:cellFrame]) {
            //在屏幕上
            if (cell == nil) {
                cell = [self.dataSource waterFallView:self cellAtIndex:i];
                cell.frame = cellFrame;
                [self addSubview:cell];
                
                //存放到字典中
                self.displacingCells[@(i)] = cell;
            }
            
            
        }else{
            //不在屏幕上
            if (cell) {
                //将cell从视图上移除
                [cell removeFromSuperview];
                //将cell从 self.displacingCells 中移除
                [self.displacingCells removeObjectForKey:@(i)];
                //将cell放入缓存池,以便循环利用
                [self.resuableCells addObject:cell];
            }
        }
        
    }
    
}

//判断 cell 是否在屏幕内
- (BOOL)isInframe:(CGRect)frame{
    
    if ((CGRectGetMaxY(frame) > self.contentOffset.y) && (CGRectGetMinY(frame) < self.contentOffset.y + self.bounds.size.height))  {
        return YES;
    }else{
        return  NO;
    }
    
}

- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier{
    __block WaterFallViewCell *reusableCell = nil;
    [self.resuableCells enumerateObjectsUsingBlock:^(WaterFallViewCell  *cell, BOOL * _Nonnull stop) {
        if ([cell.identifier isEqualToString:identifier]) {
            reusableCell = cell;
            *stop = YES;
        }
    }];
    
    if (reusableCell) {
        //如果在缓存池中找到了cell，将cell从缓存池中移除
        [self.resuableCells removeObject:reusableCell];
    }
    
    return reusableCell;
}


//有多少列
- (NSUInteger)numberOfColums{
    if ([self.dataSource respondsToSelector:@selector(numberOfColumnsInWaterfall:)]) {
        //如果实现了上面的方法
        return [self.dataSource numberOfColumnsInWaterfall:self];
    }else{
        return NumberOfColums;
    }

}

//计算间距
- (CGFloat)marginType:(WaterFallMarginType)marginType{
    if ([self.delegate respondsToSelector:@selector(waterFallView:marginType:)]) {
        //如果实现了上面的方法
        return [self.delegate waterFallView:self marginType:marginType];
    }else{
        return DefaultMargin;
    }

}

//计算cell高度
- (CGFloat)heightAtIndex:(NSUInteger)index{
    if ([self.delegate respondsToSelector:@selector(waterFallView:heightAtIndex:)]) {
        //如果实现了上面的方法
        return [self.delegate waterFallView:self heightAtIndex:index];
    }else{
       //返回默认高度
        return DefaultCellHeight;
    }
}




#pragma mark ===== 点击了哪一个cell
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    if (![self.delegate respondsToSelector:@selector(waterFallView:didSelectAtIndex:)]) return;
    
    //1.获得触摸点
    UITouch *touch = [touches anyObject];
    //2.
    //使用touch.view的时候得到的是相对于点击cell的坐标
//    CGPoint point = [touch locationInView:touch.view];
    //使用self的时候得到的相对于整个视图的坐标
    CGPoint point = [touch locationInView:self];
    __block NSNumber *selectIndex = nil;
    [self.displacingCells enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, WaterFallViewCell *cell, BOOL * _Nonnull stop) {
        if (CGRectContainsPoint(cell.frame, point)) {
            selectIndex = key;
            *stop = YES;
        }
    }];
    
    if (selectIndex) {
        [self.delegate waterFallView:self didSelectAtIndex:selectIndex.unsignedIntegerValue];
    }

}

@end
